﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cosmetic.DataEntity;

namespace Cosmetic.Logic
{
	/// <summary>
	/// tag manager class
	/// </summary>
	public class TagManager : LogicBase
    {
		private CategoryManager m_CategoryManager	= new CategoryManager();

		public enum ETagCategory
		{
			Product,
			Comment,
			Content
		}


		/// <summary>
		/// Insert a new Tag into database
		/// </summary>
		/// <param name="aTag">new Tag</param>
		public void Insert(Tag aTag)
		{
			aTag.Name	= aTag.Name.ToLower();
			m_CosmeticDC.Tags.InsertOnSubmit(aTag);
			m_CosmeticDC.SubmitChanges();
		}
		/// <summary>
		/// insert new tag into database
		/// </summary>
		/// <param name="aTagName">Tag name</param>
		/// <param name="aTagCategory">Tag category</param>
		public Tag Insert(string aTagName, ETagCategory aTagCategory)
		{
			return this.Insert(aTagName, this.GetTagCategoryByName(aTagCategory).CategoryId);
		}
		/// <summary>
		/// insert new tag into database
		/// </summary>
		/// <param name="aTagName">Tag name</param>
		/// <param name="aTagCategoryId">tag category id</param>
		private Tag Insert(string aTagName, Guid aTagCategoryId)
		{
			Tag theTag;
			if (this.CheckExists(aTagName, aTagCategoryId))
			{
				theTag	= this.GetTagByName(aTagName, aTagCategoryId);
				this.AddCount(theTag);
			}
			else
			{
				theTag					= new Tag();
				theTag.Name				= aTagName.ToLower();
				theTag.TagId			= Guid.NewGuid();
				theTag.TagCategoryId	= aTagCategoryId;
				theTag.Counts			= 1;
				theTag.CreateTime		= DateTime.Now;
				theTag.LastUseTime		= DateTime.Now;
				m_CosmeticDC.Tags.InsertOnSubmit(theTag);
				m_CosmeticDC.SubmitChanges();
			}
			return theTag;
		}

		/// <summary>
		/// get tag category by category name, if not find the category, create it.
		/// </summary>
		/// <param name="aTagCategory">tag category name</param>
		/// <returns>tag category</returns>
		private Category GetTagCategoryByName(ETagCategory aTagCategory)
		{
			Category theTagTopCategory		= this.m_CategoryManager.GetTopCategryByName(CategoryManager.ETopCategory.Tag);
			List<Category> theCategoryList	= (from theCategory in m_CosmeticDC.Categories
												where theCategory.SupCategoryId == theTagTopCategory.CategoryId && theCategory.Name == aTagCategory.ToString()
												select theCategory).ToList();
			if (theCategoryList.Count == 0)
			{
				this.CheckTagCategory();
				return this.GetTagCategoryByName(aTagCategory);
			}
			return theCategoryList[0];
		}
		
		/// <summary>
		/// check tag category whether or not exists. if not exists, create it.
		/// </summary>
		private void CheckTagCategory()
		{
			Category theTagTopCategory	= this.m_CategoryManager.GetTopCategryByName(CategoryManager.ETopCategory.Tag);
			Type theTagCategoryType		= typeof(ETagCategory);
			foreach (string theTagCategoryName in Enum.GetNames(theTagCategoryType))
			{
				ETagCategory theTagCategoyEnum	= (ETagCategory)Enum.Parse(typeof(ETagCategory), theTagCategoryName);
				List<Category> theCategoryList	= (from theCategory in m_CosmeticDC.Categories
												where theCategory.SupCategoryId == theTagTopCategory.CategoryId && theCategory.Name == theTagCategoyEnum.ToString()
												select theCategory).ToList();
				if (theCategoryList.Count == 0)
				{
					Category theTagCategory			= new Category();
					theTagCategory.Name				= theTagCategoryName;
					theTagCategory.CategoryId		= Guid.NewGuid();
					theTagCategory.SupCategoryId	= theTagTopCategory.CategoryId;
					theTagCategory.CreateTime		= DateTime.Now;
					this.m_CategoryManager.Insert(theTagCategory);
				}
			}
		}

		/// <summary>
		/// check the Tag whether or not already exist.
		/// </summary>
		/// <param name="aTagName">tag name</param>
		/// <param name="aTagCategory">TagCategory</param>
		/// <returns>if exists return true else return false</returns>
		public bool CheckExists(string aTagName, ETagCategory aTagCategory)
		{
			Category theTagCategory		= this.GetTagCategoryByName(aTagCategory);
			return this.CheckExists(aTagName, theTagCategory.CategoryId);
		}
		/// <summary>
		/// check the Tag whether or not already exist.
		/// </summary>
		/// <param name="aTagName">tag name</param>
		/// <param name="aTagCategoryId">TagCategory id</param>
		/// <returns>if exists return true else return false</returns>
		private bool CheckExists(string aTagName, Guid aTagCategoryId)
		{
			List<Tag> theTagList		= (from theTag in m_CosmeticDC.Tags
											where theTag.Name == aTagName && theTag.TagCategoryId == aTagCategoryId
											select theTag).ToList();
			return theTagList.Count > 0;
		}

		/// <summary>
		/// tag count = count + 1
		/// </summary>
		/// <param name="aTag">tag</param>
		public void AddCount(Tag aTag)
		{
			aTag.Counts++;
			aTag.LastUseTime	= DateTime.Now;
			this.Update();
		}
		/// <summary>
		/// tag count = count + 1
		/// </summary>
		/// <param name="aTagName">tag name</param>
		/// <param name="aTagCategoryId">tag category id</param>
		private void AddCount(string aTagName, Guid aTagCategoryId)
		{
			this.AddCount(this.GetTagByName(aTagName, aTagCategoryId));
		}

		/// <summary>
		/// tag count = count - 1
		/// </summary>
		/// <param name="aTag">tag</param>
		public void MinusCount(Tag aTag)
		{
			if (aTag.Counts > 0)
			{
				aTag.Counts--;
				this.Update();
			}
		}
		/// <summary>
		/// split the tag name string, every tag count = count - 1
		/// </summary>
		/// <param name="aTagsName">tags name</param>
		/// <param name="aTagCategoryId">tag category id</param>
		private void MinusCount(string aTagsName, Guid aTagCategoryId)
		{
			string[] theTagNames	= aTagsName.Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries);
			foreach (string aTagName in theTagNames)
			{
				this.MinusCount(this.GetTagByName(aTagName, aTagCategoryId));
			}			
		}
		/// <summary>
		/// split the tag name string, every tag count = count - 1
		/// </summary>
		/// <param name="aTagsName">tags name</param>
		/// <param name="aTagCategory">tag category</param>
		private void MinusCount(string aTagsName, ETagCategory aTagCategory)
		{
			this.MinusCount(aTagsName, this.GetTagCategoryByName(aTagCategory).CategoryId);
		}


		/// <summary>
		/// Delete Tag
		/// </summary>
		/// <param name="aTag">The Tag want delete</param>
		public void Delete(Tag aTag)
		{
			m_CosmeticDC.Tags.DeleteOnSubmit(aTag);
			m_CosmeticDC.SubmitChanges();
		}





		/// <summary>
		/// Get Tag by Tag Id
		/// </summary>
		/// <param name="aTagId">Tag Id</param>
		/// <returns>Tag</returns>
		public Tag GetTagById(Guid aTagId)
		{
			return m_CosmeticDC.Tags.Single(theTag => theTag.TagId == aTagId);
		}

		/// <summary>
		/// get tag by tag name and tag category
		/// </summary>
		/// <param name="aTagName">tag name</param>
		/// <param name="aTagCategory">tag category</param>
		/// <returns>the Tag</returns>
		public Tag GetTagByName(string aTagName, ETagCategory aTagCategory)
		{
			return this.GetTagByName(aTagName, this.GetTagCategoryByName(aTagCategory).CategoryId);
		}
		private Tag GetTagByName(string aTagName, Guid aTagCategoryId)
		{
			List<Tag> theTagList	= (from theTag in m_CosmeticDC.Tags
									  where theTag.Name.ToLower() == aTagName && theTag.TagCategoryId == aTagCategoryId
									  select theTag).ToList();
			if (theTagList.Count == 0)
			{
				return this.Insert(aTagName, aTagCategoryId);
			}
			return theTagList[0];
		}

		/// <summary>
		/// get tags by tag category
		/// </summary>
		/// <param name="aTagCategory">tag category</param>
		/// <returns>tag list</returns>
		public List<Tag> GetAllByCategory(ETagCategory aTagCategory)
		{
			return (from theTag in m_CosmeticDC.Tags
						where theTag.TagCategoryId == this.GetTagCategoryByName(aTagCategory).CategoryId
						&& theTag.Counts > 0
						orderby theTag.Counts descending
						select theTag).ToList();
		}

	}
}
